package com.example.testclient.netty;

import android.util.Log;

import com.example.testclient.eventBusBean.ConnectStatusBean;
import com.haoxy.common.model.FileBean;
import com.haoxy.common.model.MessageBean;

import org.greenrobot.eventbus.EventBus;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * netty客户端
 *
 * @author Medvalley
 */
public class NettyClient {
    public static final String TAG = "NETTY_TAG";

    private static volatile NettyClient mInstance = null;
    private Bootstrap bootstrap;
    private EventLoopGroup group;//netty线程模型组
    private ChannelInitClient channelInitClient;//给客户端 Channel 指定处理逻辑的 Handler
    public volatile Channel channel;//连接通道

    public static NettyClient getInstance() {
        if (mInstance == null) {
            synchronized (NettyClient.class) {
                if (mInstance == null) {
                    mInstance = new NettyClient();
                }
            }
        }
        return mInstance;
    }

    public void start(String address, int port) {
        Executors.newSingleThreadScheduledExecutor().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    group = new NioEventLoopGroup();
                    bootstrap = new Bootstrap();
                    channelInitClient = new ChannelInitClient();//给客户端 Channel 指定处理逻辑的 Handler
                    bootstrap.group(group)
                            .channel(NioSocketChannel.class)//指定为NIO模型
                            .remoteAddress(new InetSocketAddress(address, port))//IP地址及端口设置
                            .option(ChannelOption.SO_BACKLOG, 1024)//链接缓冲池的大小（ServerSocketChannel的设置）
                            .option(ChannelOption.TCP_NODELAY, true)//关闭延迟发送
                            .option(ChannelOption.SO_KEEPALIVE, true)//维持链接的活跃，清除死链接(SocketChannel的设置)
                            .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                            .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
                            .option(ChannelOption.SO_RCVBUF,1024*1024*5)
                            .option(ChannelOption.SO_SNDBUF,1024*1024*5)
                            .handler(channelInitClient);//设置handler
                    ChannelFuture future = bootstrap.connect().sync();
                    channel = future.channel();
                    //端口频道打开监听
                    future.addListener(new ChannelFutureListener() {
                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {
                            if (future.isSuccess()) {
                                Log.w(TAG, "客户端启动成功");
                            }else{
                                EventBus.getDefault().post(new ConnectStatusBean("2"));
                                Log.w(TAG, "客户端启动失败");
                            }
                        }
                    });
                    channel.closeFuture().sync();
                } catch (Exception e) {
                    EventBus.getDefault().post(new ConnectStatusBean("2"));
                    e.printStackTrace();
                    Log.w(TAG, "客户端启动失败 err:" + e.getMessage());
                } finally {
                    group.shutdownGracefully();
                }

            }
        });
    }

    /**
     * 给客户端 Channel 指定处理逻辑的 Handler
     */
    public class ChannelInitClient extends ChannelInitializer<Channel> {

        public NettyDataHandler nettyDataHandler = new NettyDataHandler();

        @Override
        protected void initChannel(Channel ch) {
            try {
                ChannelPipeline channelPipeline = ch.pipeline();
                //添加心跳机制，例：每1000ms发送一次心跳
                channelPipeline.addLast(new IdleStateHandler(3000, 3000, 3000, TimeUnit.MILLISECONDS));
                //object编码器
                channelPipeline.addLast(new ObjectEncoder());
                //object解码器
                channelPipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null)));
                //自定义专门处理业务逻辑的 Handler,添加数据处理（接收、发送、心跳）
                channelPipeline.addLast(nettyDataHandler);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭客户端
     */
    public void stop() {
        //关闭断线重连
        if (null != channelInitClient && null != channelInitClient.nettyDataHandler) {
            channelInitClient.nettyDataHandler.setReconnect(false);
        }
        if (channel != null) {
            channel.close();
            channel = null;
        }
        mInstance = null;
    }

    /**
     * 发送数据
     *
     * @param messageBean
     */
    public void sendMessage(MessageBean messageBean) {
        channelInitClient.nettyDataHandler.sendMessage(messageBean);
    }

    /**
     * 发送文件
     *
     * @param fileBean
     */
    public void sendFile(FileBean fileBean) {
        channelInitClient.nettyDataHandler.sendFile(fileBean);
    }
}
